//https://blog.csdn.net/saibeifeng187/article/details/128875642  https://blog.csdn.net/can_meng_yun/article/details/128587079

package cn.com.dragonpass.infra.settle.service.impl;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j
@Service
public class MultiThreadProcess {


    @Autowired
    private static PlatformTransactionManager transactionManager;


    public static void execTasks(List<ITask> tasks, ExecutorService executorService) throws Exception {
        ArrayList<Runnable> runnables = new ArrayList<>();
        // 线程执行完标志
        CountDownLatch taskCount = new CountDownLatch(tasks.size());
        CountDownLatch mainCount = new CountDownLatch(1);
        AtomicBoolean isCommit = new AtomicBoolean(true);
        final Exception[] exception = new Exception[1];
        for (ITask task : tasks) {
            runnables.add(new Runnable() {
                @Override
                public void run() {
                    DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
                    transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

                    TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
                    try {
                        task.task();
                        // 任务正常执行完成
                        taskCount.countDown();
                        mainCount.await();
                        if (isCommit.get()) {
                            transactionManager.commit(status);
                        } else {
                            transactionManager.rollback(status);
                        }
                    } catch (Throwable ex) {
                        isCommit.set(false);
                        transactionManager.rollback(status);
                        exception[0] = new Exception(ex.getMessage(), ex);
                        taskCount.countDown();
                    }
                }
            });
        }
        try {
            afterTransaction(mainCount, isCommit);
            for (Runnable runnable : runnables) {
                executorService.submit(runnable);
            }
            taskCount.await();
            if (!isCommit.get()) {
                // 子线程有异常
                throw new Exception(exception[0].getMessage(), exception[0]);
            }
        } catch (Throwable ex) {
            log.error(ex.getMessage(), ex);
            throw new Exception(ex.getMessage(), ex);
        }
    }

    private static void afterTransaction(CountDownLatch mainCount, AtomicBoolean isCommit) {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCompletion(int status) {
                super.afterCompletion(status);
                if (status != TransactionSynchronization.STATUS_COMMITTED) {
                    // 事务没有提交
                    log.error("error...." /* "------事务回滚" */);
                    isCommit.set(false);
                } else {
                    log.info("sucess"/* "------事务提交" */);
                }
                mainCount.countDown();
            }
        });
    }
}
